package net.sf.calibur.i18n;

import japa.parser.JavaParser;
import japa.parser.ast.CompilationUnit;
import japa.parser.ast.expr.Expression;
import japa.parser.ast.expr.MethodCallExpr;
import japa.parser.ast.expr.StringLiteralExpr;
import japa.parser.ast.visitor.VoidVisitor;
import japa.parser.ast.visitor.VoidVisitorAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.util.List;

import net.sf.calibur.util.Util;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;

import static net.sf.calibur.i18n.R.*;

/**
 * 从java源代码中，自动收集用指定方法调用国际化语言字符串转换功能方法（例如"_"）， 生成配置文件的工具。
 * 
 * @author gaobo
 * 
 */
public class XGetText {
	private static void usage(Options options) {
		// automatically generate the help statement
		HelpFormatter formatter = new HelpFormatter();
		formatter.printHelp(
				"XGetText <options> <java source file | source directory>",
				options);
	}

	private static String validateArgs(String key, File src, File out) {
		if (key == null) {
			return _("Error: method name of i18n translator not be specified, use -k to specify it.");
		}

		if (src == null) {
			return _("Error: java source file or directory not be specified.");
		} else if (src.isFile()
				&& !src.getAbsolutePath().toLowerCase().endsWith(".java")) {
			return _("Error: java source file must end with .java");
		}

		if (out == null) {
			return _("Error: output file not be specified, use -o to specify it.");
		}

		return null;
	}

	public static void main(String[] args) {
		// create the command line parser
		CommandLineParser parser = new PosixParser();

		// create the Options
		Options options = new Options();
		options.addOption("k", "key", true,
				_("Specify method name of i18n translator."));
		options.addOption("o", "out", true, _("Specify output file pathname."));
		options.addOption("h", "help", false, _("Print help information."));

		File source = null, outfile = null;
		String key = null;
		try {
			// parse the command line arguments
			CommandLine line = parser.parse(options, args);
			if (line.hasOption("help")) {
				usage(options);
				System.exit(0);
			}

			if (line.hasOption("key")) {
				key = line.getOptionValue("key");
			}

			if (line.hasOption("out")) {
				outfile = new File(line.getOptionValue("out"));
			}

			String[] otherArgs = line.getArgs();
			if (otherArgs.length > 0) {
				source = new File(otherArgs[0]);
			}

			String errmsg = validateArgs(key, source, outfile);
			if (errmsg != null) {
				System.err.println(errmsg);
				usage(options);
				System.exit(1);
			}

			XGetText x = new XGetText(key, outfile);
			x.travel(source);
		} catch (Exception e) {
			System.err.println(e.getMessage());
			e.printStackTrace();
			System.exit(1);
		}

	}

	private File outfile = null;
	private File current = null;
	private String key = null;
	private VoidVisitor<Object> methodCallVisitor = new VoidVisitorAdapter<Object>() {
//		@Override
//		public void visit(StringLiteralExpr n, Object arg) {
//			System.out.println("line:" + n.getBeginLine() + " " + n.getValue());
//			super.visit(n, arg);
//		}

		@Override
		public void visit(MethodCallExpr n, Object arg) {
			if (key.equals(n.getName())) {
				List<Expression> args = n.getArgs();
				if (!Util.isEmpty(args)) {
					Expression e = args.get(0);
					if (e instanceof StringLiteralExpr) {
						StringLiteralExpr sle = (StringLiteralExpr) e;
						System.out.print(sle.getValue() + ' ');
					} else {
						// TODO: 参数不是const string错误
					}
				} else {
					// TODO: 没有任何参数错误
				}
				System.out.println();
			}
			
			super.visit(n, arg);
		}
	};

	public XGetText(String key, File outfile) {
		this.key = key;
		this.outfile = outfile;
	}

	public void travel(File f) throws Exception {
		if (f.isFile() && f.getAbsolutePath().toLowerCase().endsWith(".java")) {
			collectI18nStrings(f);
		} else {
			File[] fs = f.listFiles();
			if (!Util.isEmpty(fs)) {
				for (File file : fs) {
					travel(file);
				}
			}
		}
	}

	public void collectI18nStrings(File file) throws Exception {
		current = file;
		System.out.println(file.getAbsolutePath());
		// creates an input stream for the file to be parsed
		FileInputStream in = new FileInputStream(file);

		CompilationUnit cu;
		try {
			// parse the file
			cu = JavaParser.parse(in);

			methodCallVisitor.visit(cu, null);
		} finally {
			in.close();
		}
	}
}
